package com.cz.ssyx.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cz.ssyx.common.auth.AuthContextHolder;
import com.cz.ssyx.common.constant.RedisConst;
import com.cz.ssyx.common.exception.MyException;
import com.cz.ssyx.common.result.ResultCodeEnum;
import com.cz.ssyx.model.product.SkuAttrValue;
import com.cz.ssyx.model.product.SkuImage;
import com.cz.ssyx.model.product.SkuInfo;
import com.cz.ssyx.model.product.SkuPoster;
import com.cz.ssyx.mq.constant.MqConst;
import com.cz.ssyx.mq.service.RabbitService;
import com.cz.ssyx.product.mapper.SkuInfoMapper;
import com.cz.ssyx.product.service.SkuAttrValueService;
import com.cz.ssyx.product.service.SkuImageService;
import com.cz.ssyx.product.service.SkuInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cz.ssyx.product.service.SkuPosterService;
import com.cz.ssyx.vo.order.TimeoutOrderVo;
import com.cz.ssyx.vo.product.SkuInfoQueryVo;
import com.cz.ssyx.vo.product.SkuInfoVo;
import com.cz.ssyx.vo.product.SkuStockLockVo;
import org.redisson.RedissonMultiLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * <p>
 * sku信息 服务实现类
 * </p>
 *
 * @author Joker
 * @since 2024-04-18
 */
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements SkuInfoService {

    @Autowired
    private SkuImageService skuImageService;

    @Autowired
    private SkuPosterService skuPosterService;

    @Autowired
    private SkuAttrValueService skuAttrValueService;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    //新增商品
    @Override
    public void saveSkuInfo(SkuInfoVo skuInfoVo) {

        //1.保存skuInfo
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(skuInfoVo, skuInfo);
        //TODO 缺少一个商品所属的仓库
        skuInfo.setWareId(1L);
        this.save(skuInfo);

        //2.保存skuPoster
        List<SkuPoster> skuPosterList = skuInfoVo.getSkuPosterList();
        if (!CollectionUtils.isEmpty(skuPosterList)){
            //遍历海报，加入商品的id
            for (SkuPoster skuPoster : skuPosterList){
                skuPoster.setSkuId(skuInfo.getId());
            }
            skuPosterService.saveBatch(skuPosterList);
        }

        //3.保存skuImage
        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (!CollectionUtils.isEmpty(skuImagesList)) {
            //遍历海报，加入商品的id
            for (SkuImage skuImage : skuImagesList) {
                skuImage.setSkuId(skuInfo.getId());
            }
            skuImageService.saveBatch(skuImagesList);
        }

        //4.保存属性分组
        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(skuInfo.getId());
            }
            skuAttrValueService.saveBatch(skuAttrValueList);
        }
    }

    //通过id返回商品信息
    @Override
    public SkuInfoVo getSkuById(Long id) {

        SkuInfoVo skuInfoVo = new SkuInfoVo();

        //1.存入商品的基本信息
        SkuInfo skuInfo = this.getById(id);
        BeanUtils.copyProperties(skuInfo, skuInfoVo);

        //2.存入商品的属性信息
        List<SkuAttrValue> skuAttrValueList = skuAttrValueService.getSkuAttrValuesBySkuId(id);
        skuInfoVo.setSkuAttrValueList(skuAttrValueList);

        //3.存入商品图片信息
        List<SkuImage> skuImageList = skuImageService.getSkuImageBySkuId(id);
        skuInfoVo.setSkuImagesList(skuImageList);

        //4.存入海报信息
        List<SkuPoster> skuPosterList = skuPosterService.getSkuPosterBySkuId(id);
        skuInfoVo.setSkuPosterList(skuPosterList);

        return skuInfoVo;
    }

    //修改商品
    @Override
    public void updateSku(SkuInfoVo skuInfoVo) {
        //1.修改skuInfo
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(skuInfoVo, skuInfo);
        this.updateById(skuInfo);

        //取出商品的id
        Long id = skuInfo.getId();

        //2.修改skuPoster
        //先删除
        LambdaQueryWrapper<SkuPoster> skuPosterLambdaQueryWrapper = new LambdaQueryWrapper<>();
        skuPosterLambdaQueryWrapper.eq(SkuPoster::getSkuId, id);
        skuPosterService.remove(skuPosterLambdaQueryWrapper);
        List<SkuPoster> skuPosterList = skuInfoVo.getSkuPosterList();
        if (!CollectionUtils.isEmpty(skuPosterList)){
            //遍历海报，加入商品的id
            for (SkuPoster skuPoster : skuPosterList){
                skuPoster.setSkuId(id);
            }
            skuPosterService.saveBatch(skuPosterList);
        }

        //3.修改skuImage
        LambdaQueryWrapper<SkuImage> imageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        imageLambdaQueryWrapper.eq(SkuImage::getSkuId, id);
        skuImageService.remove(imageLambdaQueryWrapper);

        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (!CollectionUtils.isEmpty(skuImagesList)) {
            //遍历海报，加入商品的id
            for (SkuImage skuImage : skuImagesList) {
                skuImage.setSkuId(id);
            }
            skuImageService.saveBatch(skuImagesList);
        }

        //4.修改属性分组
        LambdaQueryWrapper<SkuAttrValue> attrValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
        attrValueLambdaQueryWrapper.eq(SkuAttrValue::getSkuId, id);
        skuAttrValueService.remove(attrValueLambdaQueryWrapper);

        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(id);
            }
            skuAttrValueService.saveBatch(skuAttrValueList);
        }
    }

    //删除商品
    @Override
    public void removeSku(Long id) {
        //1.删除skuInfo
        this.removeById(id);

        //2.删除skuImage
        skuImageService.removeById(id);

        //3.删除skuPoster
        skuPosterService.removeById(id);

        //4.删除skuAttrValue
        skuAttrValueService.removeById(id);

        //发送mq消息，删除es中的数据
        rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,
                                MqConst.ROUTING_GOODS_DELETE, id);
    }

    //批量删除商品
    @Override
    public void batchRemoveSku(List<Long> idList) {
        //1.删除skuInfo
        this.removeByIds(idList);

        //2.删除skuImage
        skuImageService.removeByIds(idList);

        //3.删除skuPoster
        skuPosterService.removeByIds(idList);

        //4.删除skuAttrValue
        skuAttrValueService.removeByIds(idList);
    }

    //商品上架
    @Override
    public void publishSku(Long id, Integer status) {
        if (status == 1) { //上架
            SkuInfo skuInfo = this.getById(id);
            skuInfo.setPublishStatus(status);
            this.updateById(skuInfo);
            //发送mq上架消息
            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,
                                      MqConst.ROUTING_GOODS_UPPER,
                                        id);
        }else { //下架
            SkuInfo skuInfo = this.getById(id);
            skuInfo.setPublishStatus(status);
            this.updateById(skuInfo);
            //发送mq下架消息
            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,
                                      MqConst.ROUTING_GOODS_LOWER,
                                        id);
        }
    }

    //商品审核
    @Override
    public void checkSku(Long id, Integer status) {
        SkuInfo skuInfo = this.getById(id);
        skuInfo.setCheckStatus(status);
        this.updateById(skuInfo);
    }

    //是否新人专享
    @Override
    public void isNewPersonSku(Long id, Integer status) {
        SkuInfo skuInfo = this.getById(id);
        skuInfo.setIsNewPerson(status);
        this.updateById(skuInfo);
    }

    //根据商品id列表返回商品信息列表
    @Override
    public List<SkuInfo> findSkuInfoList(List<Long> skuIdList) {
        LambdaQueryWrapper<SkuInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SkuInfo::getId, skuIdList);
        List<SkuInfo> list = this.list(queryWrapper);
        return list;
    }

    //根据关键词查询商品信息
    @Override
    public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
        LambdaQueryWrapper<SkuInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(!StringUtils.isEmpty(keyword), SkuInfo::getSkuName, keyword);
        return this.list(queryWrapper);
    }

    //获取所有新人专享商品
    @Override
    public List<SkuInfo> findNewPersonSkuInfoList() {
        //做一个分页，只取出前三个商品
        Page<SkuInfo> skuInfoPage = new Page<>(1, 3);

        //加入条件： 新人专享 上架状态 根据库存排序
        LambdaQueryWrapper<SkuInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SkuInfo::getIsNewPerson, 1);
        queryWrapper.eq(SkuInfo::getPublishStatus, 1);
        queryWrapper.orderByDesc(SkuInfo::getStock);

        Page<SkuInfo> page = this.page(skuInfoPage, queryWrapper);
        List<SkuInfo> skuInfoList = page.getRecords();
        return skuInfoList;
    }

    //获取商品的所有信息
    @Override
    public SkuInfoVo getSkuInfoVoById(Long skuId) {
        SkuInfoVo skuInfoVo = new SkuInfoVo();
        SkuInfo skuInfo = this.getById(skuId);

        //复制基本信息
        BeanUtils.copyProperties(skuInfo, skuInfoVo);

        //封装海报列表
        List<SkuPoster> skuPosterList = skuPosterService.getSkuPosterBySkuId(skuId);
        skuInfoVo.setSkuPosterList(skuPosterList);

        //封装图片列表
        List<SkuImage> skuImageList = skuImageService.getSkuImageBySkuId(skuId);
        skuInfoVo.setSkuImagesList(skuImageList);

        //封装商品属性
        List<SkuAttrValue> skuAttrValueList = skuAttrValueService.getSkuAttrValuesBySkuId(skuId);
        skuInfoVo.setSkuAttrValueList(skuAttrValueList);

        return skuInfoVo;
    }

    //验证并锁定库存
    @Override
    public Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo) {
        //1.非空判断
        if (CollectionUtils.isEmpty(skuStockLockVoList)) {
            throw new MyException(ResultCodeEnum.DATA_ERROR);
        }

        //2.遍历，验证库存并锁定
        skuStockLockVoList.forEach(this::checkLock);

        //3.如果有一个商品锁定失败，则全部解锁
        //anyMath: 只要有一个商品的isLock为false，则返回true
        boolean flag = skuStockLockVoList.stream().anyMatch(skuStockLockVo -> !skuStockLockVo.getIsLock());
        if (flag) {
            //有一个商品没有锁定，全部解锁
            skuStockLockVoList.stream().filter(SkuStockLockVo::getIsLock)
                    .forEach(skuStockLockVo -> baseMapper.unlockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum()));
            //即锁定失败
            return false;
        }

        //4.如果都锁定成功，redis缓存数据，后面要解锁和减少库存
        redisTemplate.opsForValue().set(RedisConst.SROCK_INFO + orderNo, skuStockLockVoList);
        return true;
    }

    //减库存
    @Override
    public void reduceStock(String orderNo) {
        //这里在之前验证锁定库存的最后在redis中缓存了被锁商品的信息。
        List<SkuStockLockVo> skuStockLockVoList = (List<SkuStockLockVo>) redisTemplate.opsForValue().get(RedisConst.SROCK_INFO + orderNo);
        //根据redis中缓存的信息
        if (!CollectionUtils.isEmpty(skuStockLockVoList)) {
            skuStockLockVoList.forEach(skuStockLockVo -> {
                Long skuId = skuStockLockVo.getSkuId();
                SkuInfo skuInfo = this.getById(skuId);
                //更新库存
                skuInfo.setStock(skuInfo.getStock() - skuInfo.getLockStock());
                //更新销量
                skuInfo.setSale(skuInfo.getSale() + skuInfo.getLockStock());
                //更新锁定库存
                skuInfo.setLockStock(0);
                this.updateById(skuInfo);
            });
            redisTemplate.delete(RedisConst.SROCK_INFO + orderNo);
        }
    }

    //验证库存并锁定
    private void checkLock(SkuStockLockVo skuStockLockVo) {
        //获取一个公平锁
        RLock rLock = redissonClient.getFairLock(RedisConst.SKUKEY_PREFIX + skuStockLockVo.getSkuId());
        //加锁
        rLock.lock();
        try {
            //验证库存
            SkuInfo skuInfo = baseMapper.checkStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
            //如果没有满足条件设置isLock为false
            if (skuInfo == null) {
                skuStockLockVo.setIsLock(false);
                return;
            }
            //如果满足条件， 上锁（商品上锁）
            Integer row = baseMapper.lockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
            if (row == 1) {
                skuStockLockVo.setIsLock(true);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            //解锁
            rLock.unlock();
        }

    }

    // 因超时未付款而解除锁定库存
    public void releaseStock(HashMap<Long, Integer> TimeoutOrderMap) {
        TimeoutOrderMap.forEach((key, value) -> {
            baseMapper.unlockStock(key, value);
        });
    }

    //分页条件查看sku列表
    @Override
    public Page<SkuInfo> getPageList(Page<SkuInfo> skuInfoPage, SkuInfoQueryVo skuInfoQueryVo) {

        String keyword = skuInfoQueryVo.getKeyword();
        String skuType = skuInfoQueryVo.getSkuType();
        Long categoryId = skuInfoQueryVo.getCategoryId();

        LambdaQueryWrapper<SkuInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(!StringUtils.isEmpty(keyword), SkuInfo::getSkuName, keyword);
        queryWrapper.like(!StringUtils.isEmpty(skuType), SkuInfo::getSkuType, skuType);
        queryWrapper.like(!StringUtils.isEmpty(categoryId), SkuInfo::getCategoryId, categoryId);
        queryWrapper.orderByDesc(SkuInfo::getCreateTime);
        Page<SkuInfo> page = this.page(skuInfoPage, queryWrapper);
        return  page;
    }

}
